package com.shkco.xbjcc.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.shkco.exception.GlobalExceptionCode;
import com.shkco.result.JSONResult;
import com.shkco.utils.AssertUtil;
import com.shkco.utils.BitStatesUtils;
import com.shkco.xbjcc.constants.IntegralLogConstants;
import com.shkco.xbjcc.constants.RedisSmsConstants;
import com.shkco.xbjcc.constants.UserConstants;
import com.shkco.xbjcc.domain.*;
import com.shkco.xbjcc.dto.RegisterPhoneDto;
import com.shkco.xbjcc.dto.SmsDto;
import com.shkco.xbjcc.feign.LoginService;
import com.shkco.xbjcc.mapper.UserInviteCodeMapper;
import com.shkco.xbjcc.mapper.UserMapper;
import com.shkco.xbjcc.service.*;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;


/**
 * <p>
 * 会员登录账号 服务实现类
 * </p>
 *
 * @author whale
 * @since 2022-09-23
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private LoginService loginService;

    @Autowired
    private IUserBaseInfoService userBaseInfoService;

    @Autowired
    private IUserAccountService userAccountService;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private IUserInviteCodeService userInviteCodeService;

    @Autowired
    private IUserIntegralService userIntegralService;

    @Autowired
    private IUserIntegralLogService userIntegralLogService;

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void register(RegisterPhoneDto registerPhoneDto) {
        String smsCode = registerPhoneDto.getSmsCode();
        String password = registerPhoneDto.getPassword();
        Integer regChannel = registerPhoneDto.getRegChannel();
        String mobile = registerPhoneDto.getMobile();
        String rediskey = String.format(RedisSmsConstants.REDIS_REGISTER_PHONE_KEY, mobile);
        Object o = redisTemplate.opsForValue().get(rediskey);
        // 校验短信验证码是否为空
        AssertUtil.isNotNull(o, GlobalExceptionCode.PHONE_CODE_IS_NULL);
        SmsDto smsDto = (SmsDto)o;
        // 校验短信验证码是否正确
        AssertUtil.isEquals(smsCode,smsDto.getCode(),GlobalExceptionCode.PHONE_CODE_MISTAKE);
        // 根据手机号查询用户
        User user = selectUser(mobile);
        // 判断用户是否已注册
        AssertUtil.isNull(user,GlobalExceptionCode.USER_REGISTERED);
        // 保存login
        JSONResult jsonResult = saveLogin(registerPhoneDto);
        // 断言
        AssertUtil.isTrue(jsonResult.isSuccess(),GlobalExceptionCode.USER_SAVE);
        AssertUtil.isNotNull(jsonResult.getData(),GlobalExceptionCode.ERROR);
        // 保存相关表信息
        Long loginId = Long.valueOf(jsonResult.getData().toString());
        Long userId = saveUser(loginId,registerPhoneDto);
        initUserBaseInfo(userId,regChannel);
        initUserAccount(userId);

        String inviteCode = registerPhoneDto.getInviteCode();
        UserInviteCode userInviteCode = userInviteCodeService.findByCode(inviteCode);
        AssertUtil.isNotNull(userInviteCode,GlobalExceptionCode.INVITECODE_MISTAKE);
        Long userId1 = userInviteCode.getUserId();
        User user1 = userMapper.selectById(userId1);
        String nickName = user1.getNickName();
        UserIntegral userIntegral = userIntegralService.findByUsername(nickName);
        userIntegral.setCommentNumber(userIntegral.getCommentNumber() + IntegralLogConstants.REGISTERED_GIVING_VALUE);
        userIntegral.setCourseNumber(userIntegral.getCourseNumber() + IntegralLogConstants.REGISTERED_GIVING_VALUE);
        userIntegralService.update(userIntegral,null);
        // 积分
        integralLog();
        // 成长值
        growthLog();
    }

    private void growthLog() {
        UserIntegralLog userIntegralLog = new UserIntegralLog();
        userIntegralLog.setTitle(IntegralLogConstants.GROWTH_REGISTERED_GIVING_TITEL);
        userIntegralLog.setContent(IntegralLogConstants.GROWTH_REGISTERED_GIVING_CONTENT);
        userIntegralLogService.insert(userIntegralLog);
    }

    private void integralLog() {
        UserIntegralLog userIntegralLog = new UserIntegralLog();
        userIntegralLog.setTitle(IntegralLogConstants.INTEGRAL_REGISTERED_GIVING_TITEL);
        userIntegralLog.setContent(IntegralLogConstants.INTEGRAL_REGISTERED_GIVING_CONTENT);
        userIntegralLogService.insert(userIntegralLog);
    }

    @Override
    public User findByPhone(String phone) {
        return userMapper.findByMobile(phone);
    }

    @Override
    public User findById(Long id) {
        return userMapper.findById(id);
    }

    private void initUserAccount(Long userId) {
        UserAccount userAccount = new UserAccount();
        userAccount.setCreateTime(new Date().getTime());
        userAccount.setPassword(UserConstants.USER_PASSWORD);
        userAccount.setId(userId);
        userAccount.setUsableAmount(new BigDecimal(0));
        userAccount.setFrozenAmount(new BigDecimal(0));
        userAccountService.insert(userAccount);
    }

    private void initUserBaseInfo(Long userId,Integer regChannel) {
        UserBaseInfo userBaseInfo = new UserBaseInfo();
        userBaseInfo.setId(userId);
        userBaseInfo.setRegChannel(regChannel);
        userBaseInfo.setCreateTime(new Date().getTime());
        userBaseInfoService.insert(userBaseInfo);
    }


    private Long saveUser(Long loginId, RegisterPhoneDto registerPhoneDto) {
        User user = new User();
        user.setCreateTime(new Date().getTime());
        user.setNickName(registerPhoneDto.getMobile());
        user.setPhone(registerPhoneDto.getMobile());
        user.setLoginId(loginId);
        long state1 = BitStatesUtils.addState(BitStatesUtils.OP_REGISTED, BitStatesUtils.OP_ACTIVED);
        long state = BitStatesUtils.addState(state1, BitStatesUtils.OP_AUTHED_PHONE);
        user.setBitState(state);
        insert(user);
        return user.getId();
    }

    private JSONResult saveLogin(RegisterPhoneDto registerPhoneDto) {
        Login login = new Login();
        login.setUsername(registerPhoneDto.getMobile());
        login.setPassword(registerPhoneDto.getPassword());
        login.setType(Login.USER_TYPE);
        login.setEnabled(Login.ENABLE);
        return loginService.saveOrUpdate(login);
    }

    private User selectUser(String mobile) {
        Wrapper<User> wrapper = new EntityWrapper<>();
        wrapper.eq("phone",mobile);
        return selectOne(wrapper);
    }
}
